package top.jacktgq.cas;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
 * 
 * @Title: AtomicArrayDemo.java 
 * @Package top.jacktgq.cas 
 * @Description: 原子数组的使用，以及和普通数组在多线程运行环境下的比较
 * @author CandyWall   
 * @date 2020年11月3日 上午10:58:07 
 * @version V1.0
 */
public class AtomicArrayDemo {
	public static void main(String[] args) {
		//调用普通数组的结果
		demo(
			() -> new int[10],
			(array) -> array.length,
			(array, index) -> array[index]++,
			(array) -> System.out.println(Arrays.toString(array))
		);
		//调用原子数组的结果
		demo(
			() -> new AtomicIntegerArray(10),
			(array) -> array.length(),
			(array, index) -> array.getAndIncrement(index),
			array -> System.out.println(array)
		);
	}
	
	/**
	 * 
	 * @param arraySupplier	：提供数组，可以是线程不安全数组或线程安全数组
	 * @param lengthFun		：获取数组长度的方法
	 * @param putConsumer	：自增方法，回传array，index
	 * @param printConsumer	：打印数组的方法
	 * Supplier 	提供者	无中生有			() -> 结果
	 * Function 	函数		一个参数一个结果		(参数) -> 结果
	 * BiFuction	函数		两个参数一个结果		(参数1,参数2) -> 结果
	 * Consumer		消费者	一个参数没有结果		(参数) -> void，操作
	 * BiConsumer	消费者	两个参数没有结果		(参数1,参数2) -> void，操作
	 */
	private static <T> void demo(
			Supplier<T> arraySupplier,
			Function<T, Integer> lengthFun,
			BiConsumer<T, Integer> putConsumer,
			Consumer<T> printConsumer) {
		List<Thread> threadList = new ArrayList<Thread>();
		T array = arraySupplier.get();
		Integer length = lengthFun.apply(array);
		for(int i = 0; i < length; i++) {
			threadList.add(new Thread(() -> {
				for(int j = 0; j < 10000; j++) {
					putConsumer.accept(array, j % length);
				}
			}));
		}
		
		//启动所有线程
		threadList.forEach(t -> t.start());
		//等待所有线程结束
		threadList.forEach(t -> {
			try {
				t.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
		//打印结果
		printConsumer.accept(array);
	}
}
